package com.xjrsoft.common.helper;

import cn.hutool.db.Db;
import cn.hutool.json.JSONUtil;
import com.xjrsoft.common.dbmodel.utils.DataSourceUtil;
import com.xjrsoft.common.tsmodel.TsSchemeModel;
import com.xjrsoft.core.constant.AppConstant;
import com.xjrsoft.core.tool.utils.DateUtil;
import com.xjrsoft.core.tool.utils.SpringUtil;
import com.xjrsoft.core.tool.utils.StringUtil;
import com.xjrsoft.module.buildCode.props.GlobalConfigProperties;
import com.xjrsoft.module.taskSchedule.entity.XjrTsLog;
import com.xjrsoft.module.taskSchedule.entity.XjrTsProcess;
import com.xjrsoft.module.taskSchedule.entity.XjrTsScheme;
import com.xjrsoft.module.taskSchedule.packages.BaseExecutor;
import com.xjrsoft.module.taskSchedule.service.IXjrTsLogService;
import com.xjrsoft.module.taskSchedule.service.IXjrTsProcessService;
import com.xjrsoft.module.taskSchedule.service.IXjrTsSchemeService;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.quartz.*;
import org.springframework.web.client.RestTemplate;

import javax.sql.DataSource;
import java.sql.CallableStatement;
import java.time.LocalDateTime;
import java.util.Date;
import java.util.Map;

@Slf4j
public class SchedulingHelper implements Job {

    private final IXjrTsProcessService processService;

    private final IXjrTsSchemeService schemeService;

    private final IXjrTsLogService logService;

    private final GlobalConfigProperties globalConfigProperties;

    {
        processService = SpringUtil.getBean(IXjrTsProcessService.class);
        schemeService = SpringUtil.getBean(IXjrTsSchemeService.class);
        logService = SpringUtil.getBean(IXjrTsLogService.class);
        globalConfigProperties = SpringUtil.getBean( GlobalConfigProperties.class);
    }

    @SneakyThrows
    @Override
    public void execute(JobExecutionContext context) {
        JobDataMap dataMap = context.getJobDetail().getJobDataMap();

        String processId = dataMap.getString("processId");

        XjrTsProcess process = processService.getById(processId);
        if (process == null){
            throw new JobExecutionException("找不到当前定时任务。");
        }

        XjrTsScheme scheme = schemeService.getById(process.getSchemeId());
        TsSchemeModel tsSchemeModel = JSONUtil.toBean(scheme.getScheme(), TsSchemeModel.class);

        DataSource dataSource = null;
        String dbId = tsSchemeModel.getDbId();
        if (!StringUtil.isEmpty(dbId)) {
            dataSource = DataSourceUtil.getDataSource(dbId);
        }

        Trigger trigger = context.getTrigger();
        XjrTsLog tsLog = new XjrTsLog();
        tsLog.setProcessId(processId);
        tsLog.setCreateDate(LocalDateTime.now());
        try {
            switch (tsSchemeModel.getMethodType()){
                case  1:
                    //执行sql
                    Db.use(dataSource).execute(tsSchemeModel.getStrSql());
                    break;
                case  2:
                    // 存储过程
                    CallableStatement callableStatement = dataSource.getConnection().prepareCall("{ call " + tsSchemeModel.getProcName() + " }");
                    callableStatement.execute();
                    break;
                case 3:
                    RestTemplate http = new RestTemplate();
                    Integer urlType = tsSchemeModel.getUrlType();
                    if(urlType == 0){
                        http.getForObject(tsSchemeModel.getUrl(),Map.class);
                    }
                    if(urlType == 1){
                        http.postForObject(tsSchemeModel.getUrl(),null,Map.class);
                    }
                    if(urlType == 2){
                        http.put(tsSchemeModel.getUrl(),null);
                    }
                    if(urlType == 3){
                        http.delete(tsSchemeModel.getUrl());
                    }
                    break;
                case 4:
                    String packageName = tsSchemeModel.getPackageName();
                    Map<String, BaseExecutor> clazzMap = SpringUtil.getBeansOfType(BaseExecutor.class);
                    for (Map.Entry<String, BaseExecutor> entry : clazzMap.entrySet()) {
                        BaseExecutor executor = entry.getValue();
                        if (StringUtil.equals(packageName, entry.getKey())
                                || StringUtil.equalsIgnoreCase(packageName, executor.getClass().getSimpleName())) {
                            executor.execute();
                            break;
                        } else {
                            throw new RuntimeException("找不到Package！");
                        }
                    }
                    break;
            }
            tsLog.setExecuteResult(1);
            tsLog.setDes("执行成功！");
        } catch (Exception e) {
            log.error("执行任务失败，任务id：" + processId, e);
            tsLog.setExecuteResult(2);
            tsLog.setDes("执行异常：" + e.getMessage());
//            Integer isRestart = tsSchemeModel.getIsRestart();
//            boolean isRestartJob = dataMap.getBoolean("isRestart");
//            if (!isRestartJob && isRestart != null && isRestart == 1) {
//                // 设置重启任务
//                Integer restartMinute = tsSchemeModel.getRestartMinute();
//                Integer restartNum = tsSchemeModel.getRestartNum();
//                SimpleScheduleBuilder scheduleBuilder = SimpleScheduleBuilder.repeatMinutelyForTotalCount(restartNum, restartMinute);
//                TriggerBuilder<SimpleTrigger> triggerBuilder = TriggerBuilder.newTrigger().withSchedule(scheduleBuilder)
//                        .withIdentity(processId + "_restart", AppConstant.APPLICATION_GROUP_NAME);
//                SimpleTrigger build = triggerBuilder.build();
//                JobDetail jobDetail = JobBuilder.newJob(SchedulingHelper.class).withIdentity(processId + "_restart", AppConstant.APPLICATION_GROUP_NAME).build();
//                jobDetail.getJobDataMap().put("processId", processId);
//                jobDetail.getJobDataMap().put("isRestart", true);
//                TsHelper.addJob(processId, build, jobDetail);
//            }
        }
        logService.save(tsLog);

        Integer state = process.getState();
        if(tsSchemeModel.getExecuteType() == 1){
            state = 4;
        } else {
            if (process.getState() == 1) {
                state = 2;
            }
            Date finalFireTime = trigger.getFinalFireTime();
            if (finalFireTime != null) {
                LocalDateTime endTime = DateUtil.fromDate(finalFireTime);
                if (endTime != null & endTime.isBefore(LocalDateTime.now())) {
                    state = 4;
                }
            } else if (trigger.getNextFireTime() == null) {
                state = 4;
            }
        }

        if (process.getState() != state) {
            processService.updateState(processId, state);
        }
        if (state == 4) {
            Scheduler scheduler = SpringUtil.getBean("scheduler", Scheduler.class);
            scheduler.deleteJob(new JobKey(process.getSchemeInfoId(), AppConstant.APPLICATION_GROUP_NAME));
        }
    }
}
